The most primitive of all types in the System.Threading namespace is Thread. This class represents an object-oriented wrapper around a given path of execution within a particular AppDomain. This type also defines a number of methods (both static and instance level) that allow you to create new threads within the current AppDomain, as well as to suspend, stop, and destroy a particular thread. Consider the list of core static members in Table 19-2.
Table 19-2. Key Static Members of the Thread Type
Static Member |
Meaning in Life |
---|---|
CurrentContext |
This read-only property returns the context in which the thread is currently running. |
CurrentThread |
This read-only property returns a reference to the currently running thread. |
GetDomain() GetDomainID() |
These methods return a reference to the current AppDomain or the ID of this domain in which the current thread is running. |
Sleep() |
This method suspends the current thread for a specified time. |
The Thread class also supports several instance-level members, some of which are shown in Table 19-3.
Table 19-3. Select Instance-Level Members of the Thread Type
Instance-Level Member | Meaning in Life |
---|---|
IsAlive | Returns a Boolean that indicates whether this thread has been started (and has not yet terminated or aborted). |
IsBackground | Gets or sets a value indicating whether or not this thread is a “background thread” (more details in just a moment). |
Name | Allows you to establish a friendly text name of the thread. |
Priority | Gets or sets the priority of a thread, which may be assigned a value from the ThreadPriority enumeration. |
ThreadState | Gets the state of this thread, which may be assigned a value from the ThreadState enumeration. |
Abort() | Instructs the CLR to terminate the thread as soon as possible. |
Interrupt() | Interrupts (e.g., wakes) the current thread from a suitable wait period. |
Join() | Blocks the calling thread until the specified thread (the one on which Join() is called) exits. |
Resume() | Resumes a thread that has been previously suspended. |
Start() | Instructs the CLR to execute the thread ASAP. |
Suspend() | Suspends the thread. If the thread is already suspended, a call to Suspend() has no effect. |
Note Aborting or suspending an active thread is generally considered a bad idea. When you do so, there is a chance (however small) that a thread could “leak” its workload when disturbed or terminated.
Recall that the entry point of an executable assembly (i.e., the Main() method) runs on the primary thread of execution. To illustrate the basic use of the Thread type, assume you have a new Console Application named ThreadStats. As you know, the static Thread.CurrentThread property retrieves a Thread object that represents the currently executing thread. Once you have obtained the current thread, you are able to print out various statistics:
// Be sure to import the System.Threading namespace. static void Main(string[] args) { Console.WriteLine("***** Primary Thread stats *****\n"); // Obtain and name the current thread. Thread primaryThread = Thread.CurrentThread; primaryThread.Name = "ThePrimaryThread"; // Show details of hosting AppDomain/Context. Console.WriteLine("Name of current AppDomain: {0}", Thread.GetDomain().FriendlyName); Console.WriteLine("ID of current Context: {0}", Thread.CurrentContext.ContextID); // Print out some stats about this thread. Console.WriteLine("Thread Name: {0}", primaryThread.Name); Console.WriteLine("Has thread started?: {0}", primaryThread.IsAlive); Console.WriteLine("Priority Level: {0}", primaryThread.Priority); Console.WriteLine("Thread State: {0}", primaryThread.ThreadState); Console.ReadLine(); }
***** Primary Thread stats ***** Name of current AppDomain: ThreadStats.exe ID of current Context: 0 Thread Name: ThePrimaryThread Has thread started?: True Priority Level: Normal Thread State: Running
While this code is more or less self-explanatory, do notice that the Thread class supports a property called Name. If you do not set this value, Name will return an empty string. However, once you assign a friendly string moniker to a given Thread object, you can greatly simplify your debugging endeavors. If you are making use of Visual Studio 2010, you may access the Threads window during a debugging session (select Debug > Windows > Threads). As you can see from Figure 19-1, you can quickly identify the thread you wish to diagnose.
Figure 19-1
Next, notice that the Thread type defines a property named Priority. By default, all threads have a priority level of Normal. However, you can change this at any point in the thread’s lifetime using the ThreadPriority property and the related System.Threading.ThreadPriority enumeration:
public enum ThreadPriority { Lowest, BelowNormal, Normal, // Default value. AboveNormal, Highest }
If you were to assign a thread’s priority level to a value other than the default (ThreadPriority.Normal), understand that you would have no direct control over when the thread scheduler switches between threads. In reality, a thread’s priority level offers a hint to the CLR regarding the importance of the thread’s activity. Thus, a thread with the value ThreadPriority.Highest is not necessarily guaranteed to be given the highest precedence.
Again, if the thread scheduler is preoccupied with a given task (e.g., synchronizing an object, switching threads, or moving threads), the priority level will most likely be altered accordingly. However, all things being equal, the CLR will read these values and instruct the thread scheduler how to best allocate time slices. Threads with an identical thread priority should each receive the same amount of time to perform their work.
In most cases, you will seldom (if ever) need to directly alter a thread’s priority level. In theory, it is possible to jack up the priority level on a set of threads, thereby preventing lower-priority threads from executing at their required levels (so use caution).
Source Code The ThreadStats project is included under the Chapter 19 subdirectory.